#ifndef ZL_THRAED
#define ZL_THREAD

#include "Basic.h"
#include "String.h"
#include <functional>
#ifdef _MSC_VER
#include <Windows.h>
#else
#include <pthread.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <signal.h>
#endif

namespace zl
{
#ifdef _MSC_VER
	namespace threading_internal
	{
		struct WaitableData;
		struct ThreadData;
		struct MutexData;
		struct SemaphoreData;
		struct EventData;

		struct CriticalSectionData;
		struct ReaderWriterLockData;
		struct ConditionVariableData;
	};

	class WaitableObject : public Object, public NotCopyable
	{
	private:
		threading_internal::WaitableData*			waitableData;
	protected:
		WaitableObject();
		void										SetData(threading_internal::WaitableData* data);
	public:
		bool										IsCreated();
		bool										Wait();
		bool										WaitForTime(zint ms);
		static bool									WaitAll(WaitableObject** objects, zint count);
		static bool									WaitAllForTime(WaitableObject** objects, zint count, zint ms);
		static zint									WaitAny(WaitableObject** objects, zint count, bool* abandoned);
		static zint									WaitAnyForTime(WaitableObject** objects, zint count, zint ms, bool* abandoned);
	};

	class Thread : public WaitableObject
	{
		friend void InternalThreadProc(Thread* thread);
	public:
		enum ThreadState
		{
			NotStarted,
			Running,
			Paused,
			Stopped
		};
		typedef void(*ThreadProcedure)(Thread*, void*);
	private:
		threading_internal::ThreadData*				internalData;
		volatile ThreadState						threadState;
	protected:
		virtual void								Run() = 0;
	public:
		Thread();
		~Thread();
		static Thread*								CreateAndStart(ThreadProcedure procedure, void* argument = 0, bool deleteAfterStopped = true);
		static Thread*								CreateAndStart(const std::function<void()>& procedure, bool deleteAfterStopped = true);
		static void									Sleep(zint ms);
		static zint									GetCPUCount();
		static zint									GetCurrentThreadId();
		bool										Start();
		bool										Pause();
		bool										Resume();
		bool										Stop();
		ThreadState									GetState();
		void										SetCPU(zint index);
	};

	class Mutex : public WaitableObject
	{
	private:
		threading_internal::MutexData*				internalData;
	public:
		Mutex();
		~Mutex();
		bool										Create(bool owned = false, const std::wstring& name = L"");
		bool										Open(bool inheritable, const std::wstring& name);
		bool										Release();
	};

	class Semaphore : public WaitableObject
	{
	private:
		threading_internal::SemaphoreData*			internalData;
	public:
		Semaphore();
		~Semaphore();
		bool										Create(zint initialCount, zint maxCount, const std::wstring& name = L"");
		bool										Open(bool inheritable, const std::wstring& name);
		bool										Release();
		zint										Release(zint count);
	};

	class EventObject : public WaitableObject
	{
	private:
		threading_internal::EventData*				internalData;
	public:
		EventObject();
		~EventObject();
		bool										CreateAutoUnsignal(bool signaled, const std::wstring& name = L"");
		bool										CreateManualUnsignal(bool signaled, const std::wstring& name = L"");
		bool										Open(bool inheritable, const std::wstring& name);
		bool										Signal();
		bool										Unsignal();
	};

	class ThreadPoolLite : public Object
	{
	private:
		ThreadPoolLite();
		~ThreadPoolLite();
	public:
		static bool									Queue(void(*proc)(void*), void* argument);
		static bool									Queue(const std::function<void()>& proc);
		template<typename T>
		static void QueueLambda(const T& proc)
		{
			Queue(std::function<void()>(proc));
		}
	};

	class CriticalSection : public Object, public NotCopyable
	{
	private:
		friend class ConditionVariable;
		threading_internal::CriticalSectionData*	internalData;
	public:
		CriticalSection();
		~CriticalSection();
		bool										TryEnter();
		void										Enter();
		void										Leave();
	public:
		class Scope : public Object, public NotCopyable
		{
		private:
			CriticalSection*						criticalSection;
		public:
			Scope(CriticalSection& _criticalSection);
			~Scope();
		};
	};

	class ReaderWriterLock : public Object, public NotCopyable
	{
	private:
		friend class ConditionVariable;
		threading_internal::ReaderWriterLockData*	internalData;
	public:
		ReaderWriterLock();
		~ReaderWriterLock();

		bool										TryEnterReader();
		void										EnterReader();
		void										LeaveReader();
		bool										TryEnterWriter();
		void										EnterWriter();
		void										LeaveWriter();
	public:
		class ReaderScope : public Object, public NotCopyable
		{
		private:
			ReaderWriterLock*						lock;
		public:
			ReaderScope(ReaderWriterLock& _lock);
			~ReaderScope();
		};

		class WriterScope : public Object, public NotCopyable
		{
		private:
			ReaderWriterLock*						lock;
		public:
			WriterScope(ReaderWriterLock& _lock);
			~WriterScope();
		};
	};

	class ConditionVariable : public Object, public NotCopyable
	{
	private:
		threading_internal::ConditionVariableData*	internalData;
	public:
		ConditionVariable();
		~ConditionVariable();
		bool										SleepWith(CriticalSection& cs);
		bool										SleepWithForTime(CriticalSection& cs, zint ms);
		bool										SleepWithReader(ReaderWriterLock& lock);
		bool										SleepWithReaderForTime(ReaderWriterLock& lock, zint ms);
		bool										SleepWithWriter(ReaderWriterLock& lock);
		bool										SleepWithWriterForTime(ReaderWriterLock& lock, zint ms);
		void										WakeOnePending();
		void										WakeAllPendings();
	};

	typedef long LockedInt;
	class SpinLock : public Object, public NotCopyable
	{
	protected:
		volatile LockedInt							token;
	public:
		SpinLock();
		~SpinLock();
		bool										TryEnter();
		void										Enter();
		void										Leave();
	public:
		class Scope : public Object, public NotCopyable
		{
		private:
			SpinLock*								spinLock;
		public:
			Scope(SpinLock& _spinLock);
			~Scope();
		};
	};

#define SPIN_LOCK(LOCK) SCOPE_VARIABLE(SpinLock::Scope, scope, LOCK)
#define CS_LOCK(LOCK) SCOPE_VARIABLE(CriticalSection::Scope, scope, LOCK)
#define READER_LOCK(LOCK) SCOPE_VARIABLE(ReaderWriterLock::ReaderScope, scope, LOCK)
#define WRITER_LOCK(LOCK) SCOPE_VARIABLE(ReaderWriterLock::WriterScope, scope, LOCK)

	template<typename T>
	class RepeatingTaskExecutor : public Object
	{
	private:
		SpinLock								inputLock;
		T										inputData;
		volatile bool							inputDataAvailable;
		SpinLock								executingEvent;
		volatile bool							executing;

		void ExecutingProcInternal()
		{
			while (true)
			{
				bool currentInputDataAvailable;
				T currentInputData;
				SPIN_LOCK(inputLock)
				{
					currentInputData = inputData;
					inputData = T();
					currentInputDataAvailable = inputDataAvailable;
					inputDataAvailable = false;
					if (!currentInputDataAvailable)
					{
						executing = false;
						goto FINISH_EXECUTING;
					}
				}
				Execute(currentInputData);
			}
		FINISH_EXECUTING:
			executingEvent.Leave();
		}

		static void ExecutingProc(void* argument)
		{
			((RepeatingTaskExecutor<T>*)argument)->ExecutingProcInternal();
		}

	protected:
		virtual void							Execute(const T& input) = 0;

	public:
		RepeatingTaskExecutor()
			:inputDataAvailable(false)
			, executing(false)
		{
		}

		~RepeatingTaskExecutor()
		{
			EnsureTaskFinished();
		}

		void EnsureTaskFinished()
		{
			executingEvent.Enter();
			executingEvent.Leave();
		}

		void SubmitTask(const T& input)
		{
			SPIN_LOCK(inputLock)
			{
				inputData = input;
				inputDataAvailable = true;
			}
			if (!executing)
			{
				executing = true;
				executingEvent.Enter();
				ThreadPoolLite::Queue(&ExecutingProc, this);
			}
		}
	};
#else
class WaitableObject:public Object,public virtual Interface
{
public:
	virtual bool       Wait() = 0;
	virtual bool       IsCreated() = 0;
};

class Semaphore :public WaitableObject
{
private:
	sem_t             sem;
	zint              value;
	bool              isnamed;
	bool              iscreated;
public:
	Semaphore();
	~Semaphore();
	bool              Create(zint value, const WString& name = L"");
	bool              Open(const WString& name);
	bool              IsCreated();
	bool              Post();
	bool              Wait();
};

class Mutex :public WaitableObject
{
private:
	pthread_mutex_t  mutex;
	pthread_cond_t   cond;
	bool             iscreated;
public:
	Mutex();
	~Mutex();
	bool              Wait();
	bool              WakeUp();
	bool              WakeUpAll();
	bool              IsCreated();
	bool              WaitForTime(zint us);
	bool              Create();
	void              Release();
	bool              Lock();
	bool              UnLock();
};

class Thread :public WaitableObject
{
	friend void  InteralThreadProc(Thread* thread);
protected:
	pthread_t         pid;
	Semaphore         semaphore;
	void*             argument;
	void*             result;
	virtual void      Run() = 0;
public:
	typedef void(*ThreadProcedure)(Thread*, void*);
	enum ThreadState
	{
		NotStarted,
		Running,
		Paused,
		Stopped
	};
	ThreadState       state;
public:
	Thread();
	virtual ~Thread();
	bool              IsCreated();
	bool              Wait();
	bool              Pause();
	bool              Resume();
	static Thread*    Create(ThreadProcedure procedure, void* argument = 0);
	static void       Sleep(zint seconds);
private:
	static __thread zint flag;
	static struct sigaction  resumesig;
	static struct sigaction  suspendsig;
	static void       Suspendhandler(int signum);
	static void       Resumehandler(int signum);
};
#endif
};


#endif